package com.mask.im.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mask.im.business.model.entity.SysMenuEntity;
import com.mask.im.business.common.exception.BusinessException;
import com.mask.im.business.mapper.SysMenuMapper;
import com.mask.im.business.mapper.SysRoleMenuMapper;
import com.mask.im.business.model.dto.LabelOptionDTO;
import com.mask.im.business.model.dto.MenuDTO;
import com.mask.im.business.model.dto.UserMenuDTO;
import com.mask.im.business.model.entity.SysRoleMenuEntity;
import com.mask.im.business.model.vo.ConditionVO;
import com.mask.im.business.model.vo.IsHiddenVO;
import com.mask.im.business.model.vo.MenuVO;
import com.mask.im.business.service.SysMenuService;
import com.mask.im.business.common.util.BeanCopy;
import com.mask.im.business.common.util.MaskIMSecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static com.mask.im.business.common.constant.CommonConstant.COMPONENT;
import static com.mask.im.business.common.constant.CommonConstant.TRUE;


/**
 * @author jian
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenuEntity> implements SysMenuService {

	@Autowired
	private SysRoleMenuMapper sysRoleMenuMapper;

	@Override
	public List<MenuDTO> listMenus(ConditionVO conditionVO) {
		List<SysMenuEntity> sysMenuEntities = this.baseMapper.selectList(new LambdaQueryWrapper<SysMenuEntity>()
				.like(StringUtils.isNotBlank(conditionVO.getKeywords()), SysMenuEntity::getName, conditionVO.getKeywords()));

		List<SysMenuEntity> catalogs = listCatalogs(sysMenuEntities);

		Map<Integer, List<SysMenuEntity>> childrenMap = getMenuMap(sysMenuEntities);
		List<MenuDTO> menuDTOs = catalogs.stream().map(item -> {
			MenuDTO menuDTO = BeanCopy.singleCopy(item, MenuDTO.class);
			List<MenuDTO> list = BeanCopy.listCopy(childrenMap.get(item.getId()), MenuDTO.class).stream()
					.sorted(Comparator.comparing(MenuDTO::getOrderNum))
					.collect(Collectors.toList());
			menuDTO.setChildren(list);
			childrenMap.remove(item.getId());
			return menuDTO;
		}).sorted(Comparator.comparing(MenuDTO::getOrderNum)).collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(childrenMap)) {
			List<SysMenuEntity> childrenList = new ArrayList<>();
			childrenMap.values().forEach(childrenList::addAll);
			List<MenuDTO> childrenDTOList = childrenList.stream()
					.map(item -> BeanCopy.singleCopy(item, MenuDTO.class))
					.sorted(Comparator.comparing(MenuDTO::getOrderNum))
					.collect(Collectors.toList());
			menuDTOs.addAll(childrenDTOList);
		}
		return menuDTOs;
	}

	@Override
	public void saveOrUpdateMenu(MenuVO menuVO) {
		SysMenuEntity sysMenuEntity = BeanCopy.singleCopy(menuVO, SysMenuEntity.class);
		this.saveOrUpdate(sysMenuEntity);
	}

	@Override
	public void updateMenuIsHidden(IsHiddenVO isHiddenVO) {
		SysMenuEntity sysMenuEntity = BeanCopy.singleCopy(isHiddenVO, SysMenuEntity.class);
		baseMapper.updateById(sysMenuEntity);
	}

	@Override
	public void deleteMenu(Integer menuId) {
		Integer count = sysRoleMenuMapper.selectCount(new LambdaQueryWrapper<SysRoleMenuEntity>()
				.eq(SysRoleMenuEntity::getMenuId, menuId));
		if (count > 0) {
			throw new BusinessException("菜单下有角色关联");
		}
		List<Integer> menuIds = baseMapper.selectList(new LambdaQueryWrapper<SysMenuEntity>()
				.select(SysMenuEntity::getId)
				.eq(SysMenuEntity::getParentId, menuId))
				.stream()
				.map(SysMenuEntity::getId)
				.collect(Collectors.toList());
		menuIds.add(menuId);
		baseMapper.deleteBatchIds(menuIds);
	}

	@Override
	public List<LabelOptionDTO> listMenuOptions() {
		List<SysMenuEntity> sysMenuEntities = baseMapper.selectList(new LambdaQueryWrapper<SysMenuEntity>()
				.select(SysMenuEntity::getId, SysMenuEntity::getName, SysMenuEntity::getParentId, SysMenuEntity::getOrderNum));
		List<SysMenuEntity> catalogs = listCatalogs(sysMenuEntities);
		Map<Integer, List<SysMenuEntity>> childrenMap = getMenuMap(sysMenuEntities);
		return catalogs.stream().map(item -> {
			List<LabelOptionDTO> list = new ArrayList<>();
			List<SysMenuEntity> children = childrenMap.get(item.getId());
			if (CollectionUtils.isNotEmpty(children)) {
				list = children.stream()
						.sorted(Comparator.comparing(SysMenuEntity::getOrderNum))
						.map(sysMenuEntity -> LabelOptionDTO.builder()
								.id(sysMenuEntity.getId())
								.label(sysMenuEntity.getName())
								.build())
						.collect(Collectors.toList());
			}
			return LabelOptionDTO.builder()
					.id(item.getId())
					.label(item.getName())
					.children(list)
					.build();
		}).collect(Collectors.toList());
	}

	@Override
	public List<UserMenuDTO> listUserMenus() {
		Integer id = MaskIMSecurityUtils.getUserId();
		List<SysMenuEntity> sysMenuEntities = this.baseMapper.listMenusByUserInfoId(id);
		List<SysMenuEntity> catalogs = listCatalogs(sysMenuEntities);
		Map<Integer, List<SysMenuEntity>> childrenMap = getMenuMap(sysMenuEntities);
		List<UserMenuDTO> userMenuDTOS = convertUserMenuList(catalogs, childrenMap);
		return userMenuDTOS;
	}


	private List<SysMenuEntity> listCatalogs(List<SysMenuEntity> sysMenuEntities) {
		return sysMenuEntities.stream()
				.filter(item -> Objects.isNull(item.getParentId()))
				.sorted(Comparator.comparing(SysMenuEntity::getOrderNum))
				.collect(Collectors.toList());
	}

	private Map<Integer, List<SysMenuEntity>> getMenuMap(List<SysMenuEntity> sysMenuEntities) {
		return sysMenuEntities.stream()
				.filter(item -> Objects.nonNull(item.getParentId()))
				.collect(Collectors.groupingBy(SysMenuEntity::getParentId));
	}

	private List<UserMenuDTO> convertUserMenuList(List<SysMenuEntity> catalogList, Map<Integer, List<SysMenuEntity>> childrenMap) {
		return catalogList.stream().map(item -> {
			UserMenuDTO userMenuDTO = new UserMenuDTO();
			List<UserMenuDTO> list = new ArrayList<>();
			List<SysMenuEntity> children = childrenMap.get(item.getId());
			if (CollectionUtils.isNotEmpty(children)) {
				userMenuDTO = BeanCopy.singleCopy(item, UserMenuDTO.class);
				list = children.stream()
						.sorted(Comparator.comparing(SysMenuEntity::getOrderNum))
						.map(sysMenuEntity -> {
							UserMenuDTO dto = BeanCopy.singleCopy(sysMenuEntity, UserMenuDTO.class);
							dto.setHidden(sysMenuEntity.getIsHidden().equals(TRUE));
							return dto;
						})
						.collect(Collectors.toList());
			} else {
				userMenuDTO.setPath(item.getPath());
				userMenuDTO.setComponent(COMPONENT);
				list.add(UserMenuDTO.builder()
						.path("")
						.name(item.getName())
						.icon(item.getIcon())
						.component(item.getComponent())
						.build());
			}
			userMenuDTO.setHidden(item.getIsHidden().equals(TRUE));
			userMenuDTO.setChildren(list);
			return userMenuDTO;
		}).collect(Collectors.toList());
	}

}

